/**
 * 
 */
package com.module.bp.bus;

import java.awt.Point;

import com.dalonedrau.vectors.Vector2;
import com.module.bp.player.BPConsts;

/**
 * @author Donald
 */
public final class BPHexMap {
	/** the size of a hex in pixels. */
	private static final int	HEX_SIZE	= 64;
	/** the singleton instance. */
	private static BPHexMap		instance;
	/**
	 * Gets the singleton instance.
	 * @return {@link BPHexMap}
	 */
	public static BPHexMap getInstance() {
		if (BPHexMap.instance == null) {
			BPHexMap.instance = new BPHexMap(20, 23);
		}
		return BPHexMap.instance;
	}
	/** the number of columns in the map. */
	private int			cols;
	/** the list of hexes by type. */
	private int[]		hexes;
	/** the list of hexes by name. */
	private char[][]	names;
	/** the number of rows in the map. */
	private int			rows;
	/**
	 * Creates a new instance of {@link BPHexMap}.
	 * @param c the number of columns in the map
	 * @param r the number of rows in the map
	 */
	private BPHexMap(final int c, final int r) {
		cols = c;
		rows = r;
		hexes = new int[r * c];
		names = new char[r * c][];
	}
	/**
	 * Gets the number of columns in the map.
	 * @return <code>int</code>
	 */
	public int getCols() {
		return cols;
	}
	/**
	 * Gets the center point for a specific hex, based on a defined map size of
	 * 976px wide by 1488px high, and the map's cartesian coordinates defined as
	 * the left-most point is 0, and the bottom-most point is 0.
	 * @param col the hex column being looked up
	 * @param row the hex row being looked up
	 * @return {@link Point}
	 */
	public Vector2 getHexCenterPoint(final int col, final int row) {
		// hex 1,1 is at the top, left of the map
		// the top left point of the map is 0, 1488
		// to get the top, left corner of a hex, go to 1,1, and move to the hex
		// move down from hex 1
		int x = BPHexMap.HEX_SIZE / 2, y = 1488 - BPHexMap.HEX_SIZE / 2;
		int xHexDiff = (col - 1) / 2;
		// for even-numbered columns, move over to hex 2,1
		if (col % 2 == 0) {
			x += BPHexMap.HEX_SIZE * 3 / 4;
			xHexDiff = (col - 2) / 2;
			y -= BPHexMap.HEX_SIZE / 2;
		}
		// move vertically down to row
		int yHexDiff = row - 1;
		y -= yHexDiff * BPHexMap.HEX_SIZE;
		// move horizontally over to column
		x += xHexDiff * (BPHexMap.HEX_SIZE * 3 / 2);
		return new Vector2(x, y);
	}
	/**
	 * Gets the hex location based on its center point.
	 * @param x
	 * @param y
	 * @return {@link Vector2}
	 */
	public Vector2 getHexFromCenterPoint(final int x, final int y) {
		Vector2 v = null;
		if (x > 0
				&& y > 0
				&& x % 2 == 0) { // x must be even
			if (x % 32 == 0) { // odd-numbered row
				int col = x / 32;
				if (col > 1) {
					col = (col - 1) / 3 * 2 + 1;
				}
				if (y % 32 == 0) {
					int row = y / 32;
					if (row > 1) {
						row = (row - 1) / 2 + 1;
					}
				}
			} else if ((x - 32) % 48 == 0) { // even
				int col = (x - 32) / 48 + 1;
				if (y % 64 == 0) {
					int row = y / 64;
				}
			}
		}
		return v;
	}
	/**
	 * Gets the left-bottom point for a specific hex, based on a defined map
	 * size of 976px wide by 1488px high, and the map's cartesian coordinates
	 * defined as the origin at 0, 0.
	 * @param col the hex column being looked up
	 * @param row the hex row being looked up
	 * @return {@link Point}
	 */
	public Vector2 getHexLeftBottomPoint(final int col, final int row) {
		Vector2 pt = getHexCenterPoint(col, row);
		pt.setX(((int) pt.getX() - BPHexMap.HEX_SIZE / 2));
		pt.setY(((int) pt.getY() - BPHexMap.HEX_SIZE / 2));
		return pt;
	}
	/**
	 * Gets the hex's name.
	 * @param c the hex's column
	 * @param r the hex's row
	 * @return {@link String}
	 */
	public String getHexName(final int c, final int r) {
		// find the index
		int index = c - 1;
		index += (r - 1) * cols;
		String n = null;
		if (names[index] == null) {
			switch (this.getHexType(c, r)) {
			case BPConsts.HEX_COUNTRY:
				n = "The Countryside";
				break;
			case BPConsts.HEX_FARM:
				n = "Farmland";
				break;
			case BPConsts.HEX_FOREST:
				n = "The Forest";
				break;
			case BPConsts.HEX_HILLS:
				n = "Hill Country";
				break;
			case BPConsts.HEX_MOUNTAINS:
				n = "The Mountains";
				break;
			case BPConsts.HEX_DESERT_NO_OASIS:
			case BPConsts.HEX_DESERT_OASIS:
				n = "The Desert";
				break;
			case BPConsts.HEX_SWAMP:
				n = "The Swamps";
				break;
			default:
				break;
			}
		} else {
			n = new String(names[index]);
		}
		return n;
	}
	/**
	 * Gets the hex's name.
	 * @param v the hex's location
	 * @return {@link String}
	 */
	public String getHexName(final Vector2 v) {
		String s = " ";
		if (v != null) {
			s = getHexName((int) v.getX(), (int) v.getY());
		}
		return s;
	}
	public String getRiverName(final int index) {
		String s = "";
		// vertices 460 - 498 are the Tragoth River
		// vertices 499 - 538 are the Nesser River
		// vertices 539 - 582 are the Greater Nesser River
		if (index >= 460
				&& index <= 498) {
			s = "Tragoth River";
		} else if (index >= 499
				&& index <= 538) {
			s = "Nesser River";
		} else if (index >= 539
				&& index <= 582) {
			s = "Greater Nesser River";
		} else if (index >= 583
				&& index <= 589) {
			s = "Dienstal Branch";
		} else {
			s = "Largos River";
		}
		return s;
	}
	/**
	 * Gets the hex's name.
	 * @param vertex the hex's vertex
	 * @return {@link String}
	 */
	public String getHexName(final int vertex) {
		return getHexName(getHexVector(vertex));
	}
	/**
	 * Gets the hex's terrain type.
	 * @param c the hex's column
	 * @param r the hex's row
	 * @return <code>int</code>
	 */
	public int getHexType(final int c, final int r) {
		// find the index
		int index = c - 1;
		index += (r - 1) * cols;
		return hexes[index];
	}
	/**
	 * Gets the hex's terrain type.
	 * @param v the hex's vertex
	 * @return <code>int</code>
	 */
	public int getHexType(final int vertex) {
		return getHexType(getHexVector(vertex));
	}
	/**
	 * Gets the hex's terrain type.
	 * @param v the hex's location
	 * @return <code>int</code>
	 */
	public int getHexType(final Vector2 v) {
		return getHexType((int) v.getX(), (int) v.getY());
	}
	/**
	 * Gets the {@link Vector2} assigned to a specific map location.
	 * @param vertex the map's vertex
	 * @return {@link Vector2}
	 */
	public Vector2 getHexVector(final int vertex) {
		Vector2 v = new Vector2();
		v.setX(vertex % 20 + 1);
		v.setY(vertex / 20 + 1);
		return v;
	}
	/**
	 * Gets the vertex assigned to a specific map location.
	 * @param v the map location
	 * @return <code>int</code>
	 */
	public int getHexVertex(final Vector2 v) {
		int vertex = (int) v.getX() - 1;
		vertex += (v.getY() - 1) * 20;
		return vertex;
	}
	/**
	 * Gets the number of columns in the map.
	 * @return <code>int</code>
	 */
	public int getRows() {
		return rows;
	}
	/**
	 * Sets the hex.
	 * @param c the hex's column
	 * @param r the hex's row
	 * @param type the hex's type
	 * @param name the hex's name
	 */
	public void setHex(final int c, final int r, final int type,
			final String name) {
		// find the index
		int index = c - 1;
		index += (r - 1) * cols;
		hexes[index] = type;
		if (name != null) {
			names[index] = name.toCharArray();
		}
	}
}
